1. QMI8658 A-axis 6D 陀螺仪传感器数据手册
MPU6050原理图替代QMI8658 AD0一般接地 所以I2C 7位address为0x6B
BH1750_AHT30_BMP280_QMI8658_ESP32S3接线图
如果无法预览,请点击 此处下载 QMI8658A DatasheetRev1.0 数据手册 PDF 文件。
1. 产品概述
QMI8658 是一款低噪声、宽带宽的 6D 惯性测量单元(IMU),集成 3 轴陀螺仪和 3 轴加速度计,适用于消费电子和工业应用。其核心优势包括低延迟、小尺寸封装及丰富的运动检测功能,可通过 I3C、I2C 或 SPI 接口与主机通信。
2. 关键特性
- 低噪声性能:陀螺仪噪声密度 15 mdps/√Hz,加速度计噪声密度 150 µg/√Hz。
- 宽动态范围:陀螺仪量程 ±16°/s~±2048°/s,加速度计量程 ±2g~±16g。
- 多接口支持:MIPI™ I3C、I2C、3 线/4 线 SPI(从机模式)。
- 小尺寸封装:2.5×3.0×0.86 mm 14 引脚 LGA。
- 低功耗管理:支持低功耗模式,集成 1536 字节 FIFO 以降低系统功耗。
- 运动检测功能:内置计步器、敲击检测(Tap)、任意运动(Any-Motion)、无运动(No-Motion)及显著运动(Significant-Motion)检测。
3. 应用领域
QMI8658 适用于多种场景,包括:
- 智能手机、游戏控制器、遥控器。
- 机器人吸尘器、电动自行车/滑板车。
- 蓝牙耳机、汽车安全系统、玩具。
- 横竖屏显示控制。
4. 核心功能模块
4.1 FIFO 数据缓冲
- 1536 字节 FIFO,支持“FIFO”(满时停止写入)和“Stream”(满时覆盖旧数据)模式。
- 可配置水印中断,支持批量读取传感器数据以降低系统功耗。
4.2 运动检测
- Any-Motion/No-Motion:通过加速度斜率阈值和持续时间检测运动状态,支持多轴逻辑(OR/AND)配置。
- Significant-Motion:基于 Any-Motion 和 No-Motion 事件,检测持续显著运动。
- Tap 检测:支持单/双击识别,可配置峰值阈值、窗口时间及轴优先级。
4.3 计步器
- 基于加速度峰值检测步数,支持步长阈值、超时窗口及计数精度配置,步数通过 24 位寄存器输出。
4.4 唤醒运动(WoM)
- 超低功耗模式,通过运动检测触发中断唤醒主机,支持阈值、中断引脚及初始电平配置。
5. 接口与配置
- 串行接口:
- SPI:3 线/4 线模式,最高 15 MHz。
- I2C:标准/快速模式,最高 400 kHz。
- I3C:标准数据速率(SDR)最高 12.5 MHz。
- 寄存器控制:通过 CTRL1-CTRL9 寄存器配置传感器模式、ODR、滤波器及中断。
2. QMI8658 6轴陀螺仪传感器代码实现(ESP-IDF V6.0)
2.1 如何编写QMI8658 I2C驱动的具体流程(ESP-IDF v6.0)?
2.1.1 初始化 I2C 总线
- 使用
driver/i2c_master.h创建 I2C 总线句柄。配置SCL(GPIO 42) 和SDA(GPIO 40),波特率设为 100kHz 或 400kHz。
2.1.2 添加设备并验证 ID
- 向总线添加 QMI8658 设备(地址
0x6B,后续核实)。 - 读取
WHO_AM_I寄存器(地址0x00)。如果返回值为0x05,说明传感器连接正常。
2.1.3 配置传感器(针对陀螺仪及加速度计 Page30)
- 写入
CTRL1 0x02(0x40):设置 小端字节序以及地址自动递增(建议设置为1,方便后续突发读取),以及中断引脚配置(如果不使用中断可先保持默认)。ESP32-S3为小端芯片。
- 写入
- 写入
CTRL2 0x03(0x25):设置加速度计的输出数据速率 (ODR) 和 量程 (FSR)。加速度计: 8g, 250Hz。 - 写入
CTRL3 0x04(0x65):设置陀螺仪的输出数据速率 (ODR) 和 量程 (FSR)。陀螺仪: 1024dps, 224.2Hz。 - 写入
CTRL5 0x06(0x00):可选配置低通滤波器。建议启用,以抑制高频噪声(本次关闭)。
2.1.4 启用传感器(Page32)
- 写入
CTRL7 0x08(0x03):将gEN位 置 1,将aEN 位0 置为1,启用陀螺仪,Enable Accelerometer。
注意:配置寄存器(如
CTRL1~CTRL5、CTRL7)建议在传感器停止状态下写入(即aEN=0, gEN=0),配置完成后再启用。
2.1.5 轮询数据准备就绪标志 (DRDY——Page34)
- 在
while(1)循环中,轮询STATUS0(0x2E) 寄存器。 - 检查 bit1 (
gDA)和(aDA)。当gDA=1以及aDA=1时,表示新的陀螺仪和加速度计数据已准备好。gyroscope data and accelerometer data。
2.1.6 读取原始数据(Page 36)
- 一旦
gDA=1以及aDA=1变为 1,连续读取 6 个字节 accelerometer 从0x35LSB 低字节序AX_L<7:0>(gyroscope 从寄存器0x3B开始,即GX_L)。 - 如果已设置
CTRL1中的ADDR_AI=1,则寄存器地址会自动递增,一次i2c_master_transmit_receive即可完成。
2.1.7 数据转换(计算物理值)
- 组合
[高8位 << 8 | 低8位]得到int16_t原始值。 - 根据量程计算:
角度速率(dps) = 原始值 * FSR / 32768。 - 以 ±256 dps 为例,计算公式为:
原始值 * 256 / 32768 = 原始值 / 128。
2.2 需要重点关注的关键指令/寄存器
| 寄存器地址 | 名称 | 功能 | 必须关注点 |
|---|---|---|---|
| 0x00 | WHO_AM_I | 芯片ID | 应返回 0x05,用于验证设备 |
| 0x02 | CTRL1 | 接口控制 | bit6: ADDR_AI 必须置1以支持突发读取;bit4-3 用于启用中断引脚 |
| 0x03 | CTRL2 | 加速度计配置 | 陀螺仪、加速度计、大小端字节序 |
| 0x04 | CTRL3 | 陀螺仪配置 | 必须配置 gODR[3:0] 和 gFS[2:0] |
| 0x06 | CTRL5 | 滤波配置 | 建议设置 gLPF_EN=1 并选择合适的 gLPF_MODE |
| 0x08 | CTRL7 | 传感器启用 | 必须将 gEN 置1 |
| 0x2E | STATUS0 | 数据状态 | 必须轮询 gDA (bit1),用于判断数据是否更新 |
| 0x3B~0x40 | GX_L~GZ_H | 陀螺仪数据 | 6个寄存器连续存储 X, Y, Z 轴数据 |
2.3 QMI8658 的 I2C 地址(源自数据手册第82页 16.3.1节)
QMI8658A的 ADO 引脚接地,因此地址为 0x6B。
| ADO (SA0) 状态 | 7位 I2C 地址 | 写地址 (8位) | 读地址 (8位) |
|---|---|---|---|
| 接地 (GND) | 0x6B (0b1101011) | 0xD6 | 0xD7 |
| 接 VCC 或悬空 (默认内部上拉) | 0x6A (0b1101010) | 0xD4 | 0xD5 |
QMI8658_I2C通信流程
2.4 代码实现
C
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c_master.h"
#include "esp_log.h"
static const char *TAG = "QMI8658A";
// 引脚定义 (请根据你的实际接线修改)
#define I2C_MASTER_SCL_IO GPIO_NUM_42
#define I2C_MASTER_SDA_IO GPIO_NUM_41
#define I2C_MASTER_FREQ_HZ 400000 // 400kHz
#define I2C_PORT I2C_NUM_0
#define QMI8658_ADDR 0x6B // AD0 = connected GND, 7-bit地址
#define I2C_TIMEOUT_MS 1000
// 寄存器地址
#define REG_WHO_AM_I 0x00
#define REG_CTRL1 0x02
#define REG_CTRL2 0x03
#define REG_CTRL3 0x04
#define REG_CTRL5 0x06
#define REG_CTRL7 0x08
#define REG_STATUS0 0x2E
#define REG_ACC_DATA 0x35
#define REG_GYRO_DATA 0x3B
#define REG_RESET 0x60
// 全局I2C句柄
static i2c_master_bus_handle_t bus_handle;
static i2c_master_dev_handle_t dev_handle;
// 写寄存器
static esp_err_t qmi8658_write_reg(uint8_t reg_addr, uint8_t data) {
uint8_t write_buf[2] = {reg_addr, data};
return i2c_master_transmit(dev_handle, write_buf, sizeof(write_buf), I2C_TIMEOUT_MS);
}
// 读寄存器
static esp_err_t qmi8658_read_reg(uint8_t reg_addr, uint8_t *data, size_t len) {
return i2c_master_transmit_receive(dev_handle, ®_addr, 1, data, len, I2C_TIMEOUT_MS);
}
void app_main(void) {
ESP_LOGI(TAG, "启动 QMI8658A 简化测试");
// 1. 初始化 I2C 主机总线
i2c_master_bus_config_t bus_config = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = I2C_PORT,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_io_num = I2C_MASTER_SDA_IO,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = false, // 关闭内部上拉
};
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &bus_handle));
// 2. 添加设备
i2c_device_config_t dev_config = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = QMI8658_ADDR,
.scl_speed_hz = I2C_MASTER_FREQ_HZ,
};
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_config, &dev_handle));
// 3. 检查 WHO_AM_I
uint8_t who_am_i = 0;
ESP_ERROR_CHECK(qmi8658_read_reg(REG_WHO_AM_I, &who_am_i, 1));
if (who_am_i != 0x05) {
ESP_LOGE(TAG, "WHO_AM_I 错误: 0x%02X", who_am_i);
vTaskDelete(NULL);
} else {
ESP_LOGI(TAG, "✅ QMI8658A 连接成功!");
}
// 4. 软件复位
qmi8658_write_reg(REG_RESET, 0xB0);
vTaskDelay(pdMS_TO_TICKS(10));
// 5. 基础配置 (1024dps量程, 250Hz, 开启加速度计和陀螺仪)
qmi8658_write_reg(REG_CTRL1, 0x40); // 地址自增, 小端字节序 (Little Endian) - 匹配 ESP32-S3
qmi8658_write_reg(REG_CTRL2, 0x25); // 加速度计: 8g, 250Hz
qmi8658_write_reg(REG_CTRL3, 0x65); // 陀螺仪: 1024dps, 224.2Hz
qmi8658_write_reg(REG_CTRL5, 0x00); // 禁用低通滤波
qmi8658_write_reg(REG_CTRL7, 0x03); // 使能传感器 (Bit0=ACC, Bit1=GYRO)
vTaskDelay(pdMS_TO_TICKS(100));
ESP_LOGI(TAG, "初始化完成,开始读取数据...");
// 6. 循环读取数据
while (1) {
uint8_t status;
qmi8658_read_reg(REG_STATUS0, &status, 1);
// 检查 StatusS0: Bit0=加速度计数据就绪, Bit1=陀螺仪数据就绪
// 0x03 = 0b00000011,表示两个传感器都有新数据
if ((status & 0x03) == 0x03) {
uint8_t raw_data[12];
// 读取加速度计数据 (Register 0x35-0x3A): AX_L, AX_H, AY_L, AY_H, AZ_L, AZ_H
qmi8658_read_reg(REG_ACC_DATA, raw_data, 12); // 连续读取加速度计和陀螺仪数据,利用地址自增功能
// 读取陀螺仪数据 (Register 0x3B-0x40): GX_L, GX_H, GY_L, GY_H, GZ_L, GZ_H
// qmi8658_read_reg(REG_GYRO_DATA, raw_data + 6, 6);
// 解析原始数据 (小端字节序: 低字节_L在前,高字节_H在后)
short acc[3], gyro[3];
for (int i = 0; i < 3; i++) {
// 加速度计: raw_data[0]=AX_L, raw_data[1]=AX_H, raw_data[2]=AY_L, ...
acc[i] = (short)((raw_data[i*2+1] << 8) | raw_data[i*2]);
// 陀螺仪: raw_data[6]=GX_L, raw_data[7]=GX_H, raw_data[8]=GY_L, ...
gyro[i] = (short)((raw_data[6 + i*2+1] << 8) | raw_data[6 + i*2]);
}
// 转换为物理单位
// 加速度计: 8g 量程, 16位有符号数范围 ±32768
// 灵敏度 = 32768 / 8 = 4096 LSB/g
float acc_x = (float)acc[0] / 4096.0f;
float acc_y = (float)acc[1] / 4096.0f;
float acc_z = (float)acc[2] / 4096.0f;
// 陀螺仪: 1024dps 量程, 16位有符号数范围 ±32768
// 灵敏度 = 32768 / 1024 = 32 LSB/dps
float gyro_x = (float)gyro[0] / 32.0f;
float gyro_y = (float)gyro[1] / 32.0f;
float gyro_z = (float)gyro[2] / 32.0f;
ESP_LOGI(TAG, "ACC(g): X=%+.3f Y=%+.3f Z=%+.3f | GYRO(dps): X=%+.2f Y=%+.2f Z=%+.2f",
acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z);
}
vTaskDelay(pdMS_TO_TICKS(100)); // 10Hz 采样率 (100ms间隔)
}
}